package com.github.panchitoboy.shiro.wechat.repository;

import java.security.SecureRandom;
import java.text.ParseException;
import java.util.Date;
import java.util.UUID;

import javax.inject.Singleton;

import org.apache.shiro.authc.AuthenticationException;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.github.panchitoboy.shiro.wechat.verifier.MACVerifierExtended;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import com.thinkgem.jeesite.common.config.Config;
import com.thinkgem.jeesite.common.utils.CacheUtils;
@Component
@Singleton
public class WechatUserRepositoryImpl implements WechatUserRepository {
	private final String JWT_SHARE_KEY = "serviceItemNewCache";
	private final String JWT_SHARE_KEY_ID = "id_";
	private byte[] sharedKey;
	    
    public byte[] generateSharedKey() {
        SecureRandom random = new SecureRandom();
        byte[] sharedKey = new byte[32];
        random.nextBytes(sharedKey);
        return sharedKey;
    }

    public long getExpirationDate() {
        //return 1000 * 60 * 60 * 24 * 5;
    	return 1000 * 60 * 60 * 24 * 20;
    }

    @Override
    public String getIssuer() {
        return "issuer";
    }

/*	@Override
	public byte[] getSharedKey() {
		if (sharedKey == null) {
			sharedKey = generateSharedKey();
		}
		return sharedKey;
	}*/

	@Override
	public byte[] getSharedKey() {
		//启用分布式模式做缓存
		if(Config.isCacheDistributedEnabled()) {
			if ((byte[]) CacheUtils.get(JWT_SHARE_KEY, JWT_SHARE_KEY_ID) == null) {
				sharedKey = generateSharedKey();
				CacheUtils.put(JWT_SHARE_KEY, JWT_SHARE_KEY_ID, sharedKey);
			}

			sharedKey = (byte[]) CacheUtils.get(JWT_SHARE_KEY, JWT_SHARE_KEY_ID);
		} else {
			if (sharedKey == null) {
				sharedKey = generateSharedKey();
			}
		}
		return sharedKey;
	}

    public WechatTokenResponse createToken(UserInfo userInfo) {
    	WechatTokenResponse response = new WechatTokenResponse(userInfo, createToken((Object)userInfo));
        return response;
    }

    public String createToken(Object user) {
        try {
            JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder();

            builder.issuer(getIssuer());
            builder.subject(user.toString());
            builder.issueTime(new Date());
            builder.notBeforeTime(new Date());
            builder.expirationTime(new Date(new Date().getTime() + getExpirationDate()));
            builder.jwtID(UUID.randomUUID().toString());

            JWTClaimsSet claimsSet = builder.build();
            JWSHeader header = new JWSHeader(JWSAlgorithm.HS256);

            Payload payload = new Payload(claimsSet.toJSONObject());

            JWSObject jwsObject = new JWSObject(header, payload);

            JWSSigner signer = new MACSigner(getSharedKey());
            jwsObject.sign(signer);
            return jwsObject.serialize();
        } catch (JOSEException ex) {
            return null;
        }
    }

    public boolean validateToken(String token) {
        try {
            SignedJWT signed = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifierExtended(getSharedKey(), signed.getJWTClaimsSet());
            return signed.verify(verifier);
        } catch (ParseException ex) {
            return false;
        } catch (JOSEException ex) {
            return false;
        }
    }
    
    public String getSubject(String token) {
    	try {
            JWSObject jwsObject = JWSObject.parse(token);
            String decrypted = jwsObject.getPayload().toString();
            
            JSONObject jsonObject =  JSONObject.parseObject(decrypted);
            String subject = jsonObject.getString("sub") != null ? jsonObject.getString("sub"): null;
            return subject;
        } catch (ParseException ex) {
            throw new AuthenticationException(ex);
        }
    }
    
    public static void main(String[] argc) {
    	UserInfo userInfo = new UserInfo();
		userInfo.setName("张三");
		userInfo.setPhoneNumber("138888888888");
		userInfo.setUserTypeCode("3");
		userInfo.setOpenId("12345678922");
		
		WechatUserRepository wuri = new WechatUserRepositoryImpl();
		WechatTokenResponse wtr = wuri.createToken(userInfo);
		System.out.println(wtr.getToken());
		String c = wtr.getToken();
		System.out.println(c);
		Boolean b = wuri.validateToken(wtr.getToken());
		System.out.println(b);
		
		Boolean b2 = wuri.validateToken("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MTUxNDAzNDQsInN1YiI6IjEzODg4ODg4ODg4OCIsIm5iZiI6MTUxMzQxMjM0NCwiaXNzIjoiaXNzdWVyIiwianRpIjoiZGIzMDgzNmMtNjQ4ZC00OGQzLWIzYWEtMDcwY2RhYWIxZTQ2IiwiaWF0IjoxNTEzNDEyMzQ0fQ.b96g0KrUIVPf0e0_FoOBwyGENRH9c5FzW-NdVt7B_LE");
		System.out.println(b2);
		
		try {
            JWSObject jwsObject = JWSObject.parse(wuri.createToken(userInfo).getToken());
            String decrypted = jwsObject.getPayload().toString();
            
            JSONObject jsonObject =  JSONObject.parseObject(decrypted);
            String phoneNumber = jsonObject.getString("sub") != null ? jsonObject.getString("sub"): null;
            System.out.println(phoneNumber);

        } catch (ParseException ex) {
            throw new AuthenticationException(ex);
        }
		

	}
}
